// 第三方资源导入
const fs            = require('fs');
const parser        = require("@babel/parser");
const traverse      = require("@babel/traverse").default;
const types         = require("@babel/types");
const generator     = require("@babel/generator").default;
const usefulPlugins = require("./usefulPlugins");         // 自定义插件导入


// 从usefulPlugins文件中导出各个插件
const {varDeclarToFuncDeclar}   = usefulPlugins;
const {DeclaratorToDeclaration} = usefulPlugins;
const {standardLoop,resolveSequence}     = usefulPlugins;
const {constantFold,preDecodeObject}     = usefulPlugins;
const {keyToLiteral,isElementsLiteral}   = usefulPlugins;
const {removeDeadCode,simplifyLiteral}   = usefulPlugins;
const {isBaseLiteral,deleteRepeatDefine} = usefulPlugins;


//js混淆代码读取                  //获取运行参数，如果没有阻隔的运行参数个数，第二个和第三个给定默认的运行参数
process.argv.length > 2 ? encodeFile = process.argv[2]: encodeFile ="./encode.js";
process.argv.length > 3 ? decodeFile = process.argv[3]: decodeFile ="./decodeResult.js";


//将源代码解析为AST
let sourceCode = fs.readFileSync(encodeFile, {encoding: "utf-8"});
let ast    = parser.parse(sourceCode);

console.time("处理完毕，耗时");


//字面量解混淆
console.log("traverse Hex or Unicode String......."); // 修复十六进制和Unicode字符
traverse(ast, simplifyLiteral);


console.log("constantFold......."); // 保持代码折叠
traverse(ast, constantFold);


console.log("delete Repeat Define......."); // 删除重复定义的代码
traverse(ast, deleteRepeatDefine);


console.log("resolve Sequence......."); 
traverse(ast, standardLoop);  // 流程平坦化代码还原
traverse(ast, resolveSequence);   // 解析序列是什么意思？？？


console.log("Simpliy VariableDeclaration......"); // 变量声明类型还原

traverse(ast, DeclaratorToDeclaration);

traverse(ast, varDeclarToFuncDeclar);

function getReDefineFunction(scope,funcNames)
{
	decodeCode = "";
	scope.traverse(scope.block,{
			"FunctionDeclaration"(path)
			{
				let {id,body} = path.node;
				body = body.body;
				if (!body || body.length != 1 || 
				    !types.isReturnStatement(body[0]))
				{
					return;
				}
				let argument = body[0].argument;
				if (!types.isCallExpression(argument) || 
				    !types.isIdentifier(argument.callee))
				{
					return;
				}
				decodeCode += path.toString();
				funcNames.push(id.name);
				path.remove();
			},
	})
	return decodeCode;
}



//获取 Obfuscator 混淆的特征paths，大数组 + 自执行函数 + 解密函数
function getOldObPaths(path,funcNames)
{
	
	let {scope,node} = path;
	let {id,init}   = node;
	
	let name = id.name;

	let binding = scope.getBinding(name);
	let {constant,referencePaths} = binding;
	if (!constant || referencePaths.length < 2) 
	{
		return;
	}
	
	let obfuscatorPaths = [path];
	
	for (const referPath of referencePaths)
	{
		let AncestorPath = referPath.findParent(p => p.isFunctionDeclaration()) || 
		                   referPath.findParent(p => p.isCallExpression());
		if (!AncestorPath)
		{
			return;
		}
		if (AncestorPath.isFunctionDeclaration())
		{
			funcNames.push(AncestorPath.get('id').node.name);
		}
		else
		{
			let {arguments} = AncestorPath.node;
			if (arguments.length < 2 || !types.isIdentifier(arguments[0],{name:name}) || 
			   !types.isNumericLiteral(arguments[1]))
			{
				
				return;
			}
			if(!AncestorPath.parentPath.isExpressionStatement({expression:AncestorPath.node}))
			{
				return;
			}
			AncestorPath = AncestorPath.parentPath;
		}
		if (obfuscatorPaths.includes(AncestorPath))
		{
			continue;
		}
		obfuscatorPaths.push(AncestorPath);		
	}
	return obfuscatorPaths;
}

console.log("traverse CallExpress To ToLiteral.......");


function getNewObPaths(path, funcNames)
{
	let functionParent = path.getFunctionParent();
	if (!functionParent) return;
	let {node,scope} = functionParent;
	let name = node.id.name;
	let binding = scope.parent.getBinding(name);
	if (!binding || binding.referencePaths.length < 2)
	{
		return;
	}
	
	
	let {referencePaths} = binding;
	let obfuscatorPaths = [functionParent];
	
	for (const referPath of referencePaths)
	{
		let AncestorPath = referPath.findParent(p => p.isFunctionDeclaration()) || 
		                   referPath.findParent(p => p.isCallExpression());
		if (!AncestorPath)
		{
			return;
		}
		
		let {node,parentPath} = AncestorPath;
		
		
		if (AncestorPath.isFunctionDeclaration())
		{
			funcNames.push(AncestorPath.get('id').node.name);
		}
		else
		{
			let {arguments} = node;
			if (arguments.length < 2 || !types.isIdentifier(arguments[0],{name:name}) || 
			   !types.isNumericLiteral(arguments[1]))
			{
				return;
			}
			if(!AncestorPath.parentPath.isExpressionStatement({expression:node}))
			{
				return;
			}
			AncestorPath = parentPath;
		}
		if (obfuscatorPaths.includes(AncestorPath))
		{
			continue;
		}
		obfuscatorPaths.push(AncestorPath);		
	}
	
	return obfuscatorPaths;	
}


console.timeEnd("处理完毕，耗时");



let {code} = generator(ast,opts = {jsescOption:{"minimal":true}});

fs.writeFile(decodeFile, code, (err) => {});